
package com.dotools.compat;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.annotation.TargetApi;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;

import com.dotools.reflection.ReflectionUtils;

public class ViewMissed {

    // missed public api
    static final boolean has_setMotionEventSplittingEnabled;
    static final boolean has_isHardwareAccelerated;
    static final boolean has_setLayerType;
    static final boolean has_buildLayer;
    static final boolean has_setCameraDistance;
    static final boolean has_getLayerType;
    static final boolean has_setLayerPaint;

    // private api
    static final Method method_invalidateChildFast;

    static final int FLAG_DRAWING_CACHE_VALID;
    static final Field fieldPrivateFlags;
    static final Field fieldGroupFlags;

    static {
        final Class<?> clsView = ReflectionUtils.loadClassNoThrow(ClassLoader.getSystemClassLoader(),
                "android.view.View");

        final Class<?> clsViewGroup = ReflectionUtils.loadClassNoThrow(ClassLoader.getSystemClassLoader(),
                "android.view.ViewGroup");

        has_setMotionEventSplittingEnabled = (null != ReflectionUtils.findMethodNoThrow(clsViewGroup,
                "setMotionEventSplittingEnabled", new Class<?>[] {
                    boolean.class
                }));

        has_isHardwareAccelerated = (null != ReflectionUtils.findMethodNoThrow(clsView, "isHardwareAccelerated",
                new Class<?>[] {}));

        has_setLayerType = (null != ReflectionUtils.findMethodNoThrow(clsView, "setLayerType", new Class<?>[] {
                int.class, Paint.class
        }));

        has_buildLayer = (null != ReflectionUtils.findMethodNoThrow(clsView, "buildLayer", new Class<?>[] {}));

        has_setCameraDistance = (null != ReflectionUtils.findMethodNoThrow(clsView, "setCameraDistance",
                new Class<?>[] {
                    float.class
                }));

        has_getLayerType = (null != ReflectionUtils.findMethodNoThrow(clsView, "getLayerType", new Class<?>[] {}));

        has_setLayerPaint = (null != ReflectionUtils.findMethodNoThrow(clsView, "getLayerType", new Class<?>[] { Paint.class }));

        method_invalidateChildFast = ReflectionUtils.findMethodNoThrow(clsViewGroup, "invalidateChildFast",
                new Class<?>[] {
                        View.class, Rect.class
                });

        Field fidDCV = ReflectionUtils.findFieldNoThrow(clsView, "PFLAG_DRAWING_CACHE_VALID");
        if (fidDCV == null) {
            ReflectionUtils.findFieldNoThrow(clsView, "DRAWING_CACHE_VALID");
        }
        int flag = 0x00008000;
        try {
            fidDCV.setAccessible(true);
            flag = fidDCV.getInt(null);
        } catch (Exception e) {
            flag = 0x00008000;
        }
        FLAG_DRAWING_CACHE_VALID = flag;

        fieldPrivateFlags = ReflectionUtils.findFieldNoThrow(clsView, "mPrivateFlags");

        fieldGroupFlags = ReflectionUtils.findFieldNoThrow(clsViewGroup, "mGroupFlags");
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static void setMotionEventSplittingEnabled(ViewGroup vg, boolean split) {
        if (has_setMotionEventSplittingEnabled) {
            vg.setMotionEventSplittingEnabled(split);
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static boolean isHardwareAccelerated(View v) {
        if (has_isHardwareAccelerated) {
            return v.isHardwareAccelerated();
        }
        return false;
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static void setLayerType(View v, int layerType, Paint paint) {
        if (has_setLayerType) {
            v.setLayerType(layerType, paint);
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    public static void buildLayer(View v) {
        if (has_buildLayer) {
            v.buildLayer();
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    public static void setCameraDistance(View v, float distance) {
        if (has_setCameraDistance) {
            v.setCameraDistance(distance);
        }
    }

    public static void invalidateChildFast(ViewGroup vg, View child, final Rect dirty) {
        if (method_invalidateChildFast != null) {
            try {
                method_invalidateChildFast.invoke(vg, child, dirty);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static int getLayerType(View v) {
        if (has_getLayerType) {
            return v.getLayerType();
        }

        return 0; // View.LAYER_TYPE_NONE == 0
    }

    @TargetApi(17)
    public static void setLayerPaint(View v, Paint paint) {
        if (has_setLayerPaint) {
            v.setLayerPaint(paint);
        }
    }

    public static boolean isDrawingCacheValid(View v) {
        if (v != null && fieldPrivateFlags != null) {
            try {
                int privateFlag = fieldPrivateFlags.getInt(v);
                return ((privateFlag & FLAG_DRAWING_CACHE_VALID) == FLAG_DRAWING_CACHE_VALID);
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    public static int getPrivateFlags(View v) {
        if (v != null && fieldPrivateFlags != null) {
            try {
                int privateFlag = fieldPrivateFlags.getInt(v);
                return privateFlag;
            } catch (Exception e) {
                return 0;
            }
        }
        return 0;
    }

    public static int getGroupFlags(ViewGroup vg) {
        if (vg != null && fieldGroupFlags != null) {
            try {
                int privateFlag = fieldGroupFlags.getInt(vg);
                return privateFlag;
            } catch (Exception e) {
                return 0;
            }
        }
        return 0;
    }
}
